#include "mp3.h"
#include <string.h>

#include "esp_log.h"
#include "esp_err.h"

#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "http_stream.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"
#include "board.h"


#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"

#include "net_music.h"

static const char *TAG = "MP3";

#define MP3_INIT_DONE   0x01
#define MP3_PLAY_DONE   0x02

audio_pipeline_handle_t pipeline;
audio_element_handle_t http_stream_reader, i2s_stream_writer, mp3_decoder;
EventGroupHandle_t mp3Event = NULL;
audio_board_handle_t board_handle;
audio_element_info_t http_music_info = {0};
audio_element_info_t mp3_music_info = {0};
static unsigned char changeWaitTick = 0;
int volNow = 50;
void (*playover)();
void (*running)(int64_t pos, int64_t total, int64_t bps);
void mp3_task(void *param)
{

    esp_periph_set_handle_t set = (esp_periph_set_handle_t)param;
    ESP_LOGI(TAG, "[ 1 ] Start audio codec chip");
    board_handle = audio_board_init();
    audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_DECODE, AUDIO_HAL_CTRL_START);
    audio_hal_set_volume(board_handle->audio_hal, volNow);

    ESP_LOGI(TAG, "[2.0] Create audio pipeline for playback");
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[2.1] Create http stream to read data");
    http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
    http_stream_reader = http_stream_init(&http_cfg);

    ESP_LOGI(TAG, "[2.2] Create i2s stream to write data to codec chip");
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.type = AUDIO_STREAM_WRITER;
    i2s_stream_writer = i2s_stream_init(&i2s_cfg);

    ESP_LOGI(TAG, "[2.3] Create mp3 decoder to decode mp3 file");
    mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
    mp3_decoder = mp3_decoder_init(&mp3_cfg);

    ESP_LOGI(TAG, "[2.4] Register all elements to audio pipeline");
    audio_pipeline_register(pipeline, http_stream_reader, "http");
    audio_pipeline_register(pipeline, mp3_decoder,        "mp3");
    audio_pipeline_register(pipeline, i2s_stream_writer,  "i2s");

    ESP_LOGI(TAG, "[2.5] Link it together http_stream-->mp3_decoder-->i2s_stream-->[codec_chip]");
    const char *link_tag[3] = {"http", "mp3", "i2s"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);

    ESP_LOGI(TAG, "[2.6] Set up  uri (http as http_stream, mp3 as mp3 decoder, and default output is i2s)");
    audio_element_set_uri(http_stream_reader, "http://music.163.com/song/media/outer/url?id=1338211431");
    // http_api_get("api.seniverse.com", "/v3/weather/now.json?key=SK__R6hWJW7vsNfGP&location=hangzhou&language=en&unit=c", weather_api_deal);
    // http_api_get("s.music.163.com","/search/get/?src=lofter&type=1&filterDj=false&limit=10&offset=0&s=last+dance",weather_api_deal);
    // Example of using an audio event -- START
    ESP_LOGI(TAG, "[ 4 ] Set up  event listener");
    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);

    ESP_LOGI(TAG, "[4.1] Listening event from all elements of pipeline");
    audio_pipeline_set_listener(pipeline, evt);

    ESP_LOGI(TAG, "[4.2] Listening event from peripherals");
    audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);

    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");
    xEventGroupSetBits(mp3Event, 0x01);
    // audio_pipeline_run(pipeline);

    while (1)
    {

        audio_event_iface_msg_t msg;
        audio_element_getinfo(http_stream_reader, &http_music_info);
        // ESP_LOGI("http", "[ * ] Receive music info from mp3 decoder, byte_pos=%lld, duration=%d, total_bytes=%lld",
        //          http_music_info.byte_pos, http_music_info.duration, http_music_info.total_bytes);
        esp_err_t ret = audio_event_iface_listen(evt, &msg, 100 / portTICK_PERIOD_MS);
        if (changeWaitTick)
        {
            changeWaitTick--;
            if (changeWaitTick == 0)
            {
                audio_pipeline_resume(pipeline);
            }
        }
        audio_element_state_t el_state = audio_element_get_state(i2s_stream_writer);
        if (el_state == AEL_STATE_RUNNING && running != 0)
        {
            running(http_music_info.byte_pos, http_music_info.total_bytes, mp3_music_info.bps);
        }
        if (ret != ESP_OK)
        {
            //ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
            continue;
        }
        else
        {
            if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT
                    && msg.source == (void *) mp3_decoder
                    && msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO)
            {

                audio_element_getinfo(mp3_decoder, &mp3_music_info);
                audio_element_getinfo(http_stream_reader, &http_music_info);

                ESP_LOGI("http", "[ * ] Receive music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d,bps=%d",
                         http_music_info.sample_rates, http_music_info.bits, http_music_info.channels, http_music_info.bps);
                ESP_LOGI("mp3", "[ * ] Receive music info from mp3 decoder, byte_pos=%lld, duration=%d, total_bytes=%lld",
                         mp3_music_info.byte_pos, mp3_music_info.duration, mp3_music_info.total_bytes);


                i2s_stream_set_clk(i2s_stream_writer, http_music_info.sample_rates, http_music_info.bits, http_music_info.channels);
                continue;
            }

            /* Stop when the last pipeline element (i2s_stream_writer in this case) receives stop event */
            if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *) i2s_stream_writer
                    && msg.cmd == AEL_MSG_CMD_REPORT_STATUS && ((int)msg.data == AEL_STATUS_STATE_FINISHED))
                    // && (((int)msg.data == AEL_STATUS_STATE_STOPPED) || ((int)msg.data == AEL_STATUS_STATE_FINISHED)))
            {
                ESP_LOGW(TAG, "[ * ] Stop event received");
                xEventGroupSetBits(mp3Event, MP3_PLAY_DONE);
                if (playover)
                {
                    playover();
                }
            }
        }
    }
    // Example of using an audio event -- END

    ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_unregister(pipeline, http_stream_reader);
    audio_pipeline_unregister(pipeline, i2s_stream_writer);
    audio_pipeline_unregister(pipeline, mp3_decoder);

    audio_pipeline_remove_listener(pipeline);

    /* Stop all peripherals before removing the listener */
    esp_periph_set_stop_all(set);
    audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);

    /* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
    audio_event_iface_destroy(evt);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(http_stream_reader);
    audio_element_deinit(i2s_stream_writer);
    audio_element_deinit(mp3_decoder);
    esp_periph_set_destroy(set);
}


/// @brief 等待mp3 初始化完成
void mp3_wait_init()
{
    xEventGroupWaitBits(mp3Event, MP3_INIT_DONE, pdFALSE, pdTRUE, portMAX_DELAY);
}

/// @brief mp3初始化
/// @param set
void mp3_init(esp_periph_set_handle_t set)
{
    mp3Event = xEventGroupCreate();
    xTaskCreate(mp3_task, "mp3", 4096, set, 10, NULL);
}


/// @brief 播放mp3
/// @param url mp3网络地址
void mp3_play(const char *url)
{

    mp3_stop();
    // start new
    audio_element_set_uri(http_stream_reader, url);
    audio_pipeline_run(pipeline);
    xEventGroupClearBits(mp3Event, MP3_PLAY_DONE);
}


/// @brief 等待播放完成
void mp3_wait_idel()
{
    xEventGroupWaitBits(mp3Event, MP3_PLAY_DONE, pdFALSE, pdTRUE, portMAX_DELAY);
}

/// @brief 获取当前音量
/// @return
int mp3_get_volume()
{
    return volNow;
}


/// @brief 设置当前音量
/// @param volume
void mp3_set_volume(int volume)
{
    if (volume >= 100)
    {
        volume = 100;
    }
    else if (volume <= 0)
    {
        volume = 0;
    }
    if (audio_hal_set_volume(board_handle->audio_hal, volume) == ESP_OK)
    {
        volNow = volume;
    }
}

void mp3_stop()
{
    //stop
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);
    audio_pipeline_reset_ringbuffer(pipeline);
    audio_pipeline_reset_elements(pipeline);
}

/// @brief 暂停
void mp3_pause()
{
    audio_pipeline_pause(pipeline);
}


/// @brief 运行
void mp3_run()
{
    audio_pipeline_run(pipeline);
}

/// @brief 重新播放
void mp3_resume()
{
    audio_pipeline_resume(pipeline);
}


/// @brief 设置播放完成回调
/// @param cb
void mp3_set_over_cb(void(*cb)())
{
    playover = cb;
}

/// @brief 设置播放回调
/// @param cb
void mp3_set_running_cb(void(*cb)(int64_t pos, int64_t total, int64_t bps))
{
    running = cb;
}

void mp3_set_percent(int p)
{
    int64_t pos = (http_music_info.total_bytes >> 7) * p;
    // int64_t pos = http_music_info.total_bytes ;
    audio_pipeline_pause(pipeline);
    audio_element_set_byte_pos(http_stream_reader, pos);
    changeWaitTick = 3;

    // audio_element_set_byte_pos(mp3_decoder,mp3_music_info.total_bytes);
}
